package com.office.common.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 敏感词过滤工具类
 * author 数字牧马人
 */
public class SensitiveWordUtil {
    private static Map<String, Object> sensitiveWordMap;
    private static final String END_FLAG = "end";
    private static final int MIN_MATCH_TYPE = 1;    //最小匹配规则
    private static final int MAX_MATCH_TYPE = 2;    //最大匹配规则

    /**
     * 初始化敏感词库
     */
    public static void init() {
        // 读取敏感词库文件
        Set<String> sensitiveWords = new HashSet<>();
        try (InputStream is = SensitiveWordUtil.class.getClassLoader().getResourceAsStream("sensitive-words.txt");
             BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                sensitiveWords.add(line.trim());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 初始化敏感词Map
        sensitiveWordMap = new HashMap<>(sensitiveWords.size());
        String key;
        Map<String, Object> nowMap;
        Map<String, Object> newWordMap;
        // 迭代sensitiveWords
        for (String sensitiveWord : sensitiveWords) {
            nowMap = sensitiveWordMap;
            for (int i = 0; i < sensitiveWord.length(); i++) {
                // 转换成char型
                key = String.valueOf(sensitiveWord.charAt(i));
                // 获取
                newWordMap = (Map<String, Object>) nowMap.get(key);
                // 如果存在该key，直接赋值
                if (newWordMap != null) {
                    nowMap = newWordMap;
                } else {
                    // 不存在则，则构建一个map，同时将isEnd设置为0，因为他不是最后一个
                    newWordMap = new HashMap<>();
                    // 不是最后一个
                    newWordMap.put(END_FLAG, "0");
                    nowMap.put(key, newWordMap);
                    nowMap = newWordMap;
                }
                if (i == sensitiveWord.length() - 1) {
                    // 最后一个
                    nowMap.put(END_FLAG, "1");
                }
            }
        }
    }

    /**
     * 检查文本中是否包含敏感词
     */
    public static boolean containsSensitiveWord(String txt, int matchType) {
        boolean flag = false;
        for (int i = 0; i < txt.length(); i++) {
            int matchFlag = checkSensitiveWord(txt, i, matchType);
            if (matchFlag > 0) {
                flag = true;
                break;
            }
        }
        return flag;
    }

    /**
     * 获取文本中的敏感词
     */
    public static Set<String> getSensitiveWords(String txt, int matchType) {
        Set<String> sensitiveWords = new HashSet<>();
        for (int i = 0; i < txt.length(); i++) {
            int length = checkSensitiveWord(txt, i, matchType);
            if (length > 0) {
                sensitiveWords.add(txt.substring(i, i + length));
                if (matchType == MIN_MATCH_TYPE) {
                    i = i + length - 1;
                }
            }
        }
        return sensitiveWords;
    }

    /**
     * 替换敏感词
     */
    public static String replaceSensitiveWords(String txt, int matchType, String replaceChar) {
        String resultTxt = txt;
        Set<String> set = getSensitiveWords(txt, matchType);
        for (String word : set) {
            String replaceString = getReplaceChars(replaceChar, word.length());
            resultTxt = resultTxt.replaceAll(word, replaceString);
        }
        return resultTxt;
    }

    /**
     * 获取替换字符串
     */
    private static String getReplaceChars(String replaceChar, int length) {
        StringBuilder resultReplace = new StringBuilder(replaceChar);
        for (int i = 1; i < length; i++) {
            resultReplace.append(replaceChar);
        }
        return resultReplace.toString();
    }

    /**
     * 检查敏感词数量
     */
    private static int checkSensitiveWord(String txt, int beginIndex, int matchType) {
        boolean flag = false;
        // 记录敏感词数量
        int matchFlag = 0;
        Map<String, Object> nowMap = sensitiveWordMap;
        for (int i = beginIndex; i < txt.length(); i++) {
            char c = txt.charAt(i);
            // 获取指定key
            nowMap = (Map<String, Object>) nowMap.get(String.valueOf(c));
            if (nowMap != null) {
                matchFlag++;
                // 如果为最后一个匹配规则,结束循环，返回匹配标识数
                if ("1".equals(nowMap.get(END_FLAG))) {
                    flag = true;
                    // 最小规则，直接返回,最大规则还需继续查找
                    if (matchType == MIN_MATCH_TYPE) {
                        break;
                    }
                }
            } else {
                break;
            }
        }
        if (!flag) {
            matchFlag = 0;
        }
        return matchFlag;
    }
}
